package com.xhj.mybatis.reflection.wrapper;

import com.xhj.mybatis.reflection.MetaObject;
import com.xhj.mybatis.reflection.SystemMetaObject;
import com.xhj.mybatis.reflection.factory.ObjectFactory;
import com.xhj.mybatis.reflection.property.PropertyTokenizer;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * MapWrapper
 *
 * @author XJks
 * @description MapWrapper 类继承自 BaseWrapper，用于对 Map 类型对象进行属性包装和操作
 */
public class MapWrapper extends BaseWrapper {

    /**
     * 持有一个 Map<String, Object> 的引用，表示被包装的 Map 对象
     */
    private final Map<String, Object> map;

    /**
     * 构造方法，接收 MetaObject 和 Map 对象，初始化父类和 map 字段
     *
     * @param metaObject 反射操作的元对象
     * @param map        被包装的 Map 对象
     */
    public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
        super(metaObject); // 调用父类构造方法
        this.map = map;    // 赋值给本地 map 字段
    }

    /**
     * 获取属性值的方法
     *
     * @param prop 属性分词器，支持多级属性（如 user.address.street）
     * @return 属性的值
     */
    @Override
    public Object get(PropertyTokenizer prop) {
        // 如果属性有索引（如 list[0]），说明是集合类型
        if (prop.getIndex() != null) {
            // 解析集合对象
            Object collection = resolveCollection(prop, map);
            // 获取集合中的具体值
            return getCollectionValue(prop, collection);
        } else {
            // 否则直接从 map 中取值
            return map.get(prop.getName());
        }
    }

    /**
     * 设置属性值的方法
     *
     * @param prop  属性分词器
     * @param value 要设置的值
     */
    @Override
    public void set(PropertyTokenizer prop, Object value) {
        // 如果属性有索引，说明是集合类型
        if (prop.getIndex() != null) {
            // 解析集合对象
            Object collection = resolveCollection(prop, map);
            // 设置集合中的具体值
            setCollectionValue(prop, collection, value);
        } else {
            // 否则直接往 map 里 put
            map.put(prop.getName(), value);
        }
    }

    /**
     * 查找属性名的方法，这里直接返回原名
     *
     * @param name                属性名
     * @param useCamelCaseMapping 是否使用驼峰命名映射
     * @return 实际属性名
     */
    @Override
    public String findProperty(String name, boolean useCamelCaseMapping) {
        return name;
    }

    /**
     * 获取所有可读属性名（getter），即 map 的所有 key
     *
     * @return 属性名数组
     */
    @Override
    public String[] getGetterNames() {
        return map.keySet().toArray(new String[0]);
    }

    /**
     * 获取所有可写属性名（setter），即 map 的所有 key
     *
     * @return 属性名数组
     */
    @Override
    public String[] getSetterNames() {
        return map.keySet().toArray(new String[0]);
    }

    /**
     * 获取某个属性的 setter 类型
     *
     * @param name 属性名
     * @return 属性的类型
     */
    @Override
    public Class<?> getSetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name); // 解析属性名
        if (prop.hasNext()) { // 如果有子属性
            MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return Object.class; // 没有具体类型，返回 Object
            } else {
                return metaValue.getSetterType(prop.getChildren()); // 递归获取子属性类型
            }
        } else {
            if (map.get(name) != null) {
                return map.get(name).getClass(); // 返回实际对象的类型
            } else {
                return Object.class; // 没有值时返回 Object
            }
        }
    }

    /**
     * 获取某个属性的 getter 类型
     *
     * @param name 属性名
     * @return 属性的类型
     */
    @Override
    public Class<?> getGetterType(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name); // 解析属性名
        if (prop.hasNext()) { // 如果有子属性
            MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
            if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                return Object.class; // 没有具体类型，返回 Object
            } else {
                return metaValue.getGetterType(prop.getChildren()); // 递归获取子属性类型
            }
        } else {
            if (map.get(name) != null) {
                return map.get(name).getClass(); // 返回实际对象的类型
            } else {
                return Object.class; // 没有值时返回 Object
            }
        }
    }

    /**
     * 判断是否有 setter，这里对 map 总是返回 true
     *
     * @param name 属性名
     * @return 是否有 setter
     */
    @Override
    public boolean hasSetter(String name) {
        return true;
    }

    /**
     * 判断是否有 getter
     *
     * @param name 属性名
     * @return 是否有 getter
     */
    @Override
    public boolean hasGetter(String name) {
        PropertyTokenizer prop = new PropertyTokenizer(name); // 解析属性名
        if (prop.hasNext()) { // 如果有子属性
            if (map.containsKey(prop.getIndexedName())) { // 先判断 map 是否包含该 key
                MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
                if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
                    return true; // 虽然值为 null，但 key 存在
                } else {
                    return metaValue.hasGetter(prop.getChildren()); // 递归判断子属性
                }
            } else {
                return false; // key 不存在
            }
        } else {
            return map.containsKey(prop.getName()); // 判断 map 是否包含该 key
        }
    }

    /**
     * 实例化属性值（通常用于嵌套对象），这里新建一个 HashMap 并设置到属性中
     *
     * @param name          属性名
     * @param prop          属性分词器
     * @param objectFactory 对象工厂，用于创建新实例
     * @return 封装后的 MetaObject
     */
    @Override
    public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
        HashMap<String, Object> map = new HashMap<>(); // 新建一个 map
        set(prop, map); // 设置到当前 map 中
        // 返回新 map 的 MetaObject 包装
        return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
    }

    /**
     * 判断是否为集合类型，这里 map 不是集合，返回 false
     *
     * @return 是否为集合
     */
    @Override
    public boolean isCollection() {
        return false;
    }

    /**
     * 添加元素的方法，map 不支持，直接抛异常
     *
     * @param element 要添加的元素
     */
    @Override
    public void add(Object element) {
        throw new UnsupportedOperationException();
    }

    /**
     * 批量添加元素的方法，map 不支持，直接抛异常
     *
     * @param element 要添加的元素列表
     * @param <E>     元素类型
     */
    @Override
    public <E> void addAll(List<E> element) {
        throw new UnsupportedOperationException();
    }

}
